
#include "latex_math.h"
#include "y.tab.h"
#include <math.h>

void yyerror(const char*);

int isInteger(double d)
{
	int i = (int)d;
	if((double)i == d)
		return 1;
	else 
		return 0;
}

double factorial(double fi)
{
    int f = (int)fi;
    if((double)f != fi)
    {
      yyerror("factorials can only be computed for integers");
      return 0;
    }
	int n = 1;
	for(int i = 2;i<=f;i++)
		n = n*i;
	return (float)n;
}

double binom(double fx, double fy)
{
    int x = (int)fx;
    int y = (int)fy;
    if((double)x != fx || (double)y != fy)
      {
        yyerror("only integers in binomials.");
        return 0;
      }
	if(y < 0)
		return 0;
	if(y > x)
		return 0;
	if(x < 0)
		return 0;

	int max = x-y;
	if(y > x-y)
		max = y;
	int min = x - max;

	int result = 1;
	for(int i = max+1;i<= x;i++)
		result = result*i;
	for(int i = 2;i<= min;i++)
		result = result/i;

	return (double)result;
}

double multinom(double x, double* y)
{
	double count = y[0];
	double sum = 0;
	for(int i = 1;i<=count;i++)
		sum += y[i];
	if(sum != x)
    {
		yyerror("multinomial does not add up");
        return 0;
    }

	int answer = (int)factorial(x);
	for(int i = 1;i<=count;i++)
		answer = answer/(int)factorial(y[i]);
	
	return (double)answer;
}

double expo(double b, double p)
{
  if(b == 0)
  {
    if(p <= 0)
    {
      yyerror("0^p is only defined for positive p");
      return 0;
    }
  }

  if(b < 0)
  {
    if(p != (float)((int)p))
    {
      yyerror("negative numbers must be raised to integral powers");
      return 0;
    }
  }

  return pow(b,p);
}

double reduceBy2Pi(double input)
{
  while(input > 2*PI)
    input -= 2*PI;
  while(input < 0)
    input += 2*PI;

  return input;
}

double sin_pi(double input)
{
  input = reduceBy2Pi(input);
  if(input > PI)
    return -sin(input-PI);
  else if(input == PI)
    return 0;
  else
    return sin(input);
}

double cos_pi(double input)
{
  input = reduceBy2Pi(input);
	if(input == PI/2)
		return 0;
  if(input > PI)
    return -cos_pi(input-PI);
  else if(input == PI)
    return -1;
  else
    return cos(input);
}

double mod(double a, double b)
{
	if(!isInteger(a) || !isInteger(b))
		yyerror("modulus only takes integers");

	int x = (int)a;
	int y = (int)b;

	if(y <= 1)
		yyerror("argument to modulus must be greater than 1");
	if(x < 0)
	{
		//c doesn't handle modulus in the way mathematicians would like
		//we need   x (mod y) = -x*-1 (mod y) = -x*(y-1) (mod y)
		x = -x*(y-1);
	}

	int m = x % y;
	
	return m;

}
